package com.csun.cmny.provider.device.watch;

import com.csun.cmny.provider.device.phone.entity.PhoneDataEntity;
import com.csun.cmny.provider.device.watch.entity.*;
import com.csun.cmny.provider.model.domain.*;
import com.csun.cmny.provider.model.enums.device.DeviceStatusEnum;
import com.csun.cmny.provider.model.vo.OldmanBedRoomBuildingVo;
import com.csun.cmny.provider.service.*;
import com.csun.cmny.provider.utils.DateUtil;
import com.csun.cmny.provider.utils.WatchUtils;
import com.csun.cmny.provider.utils.map.BaiduMapUtils;
import com.csun.cmny.provider.utils.map.PointUtil;
import com.csun.cmny.util.PublicUtil;
import com.csun.cmny.util.RedisKeyUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.CharsetUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.python.google.common.collect.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.awt.geom.Point2D;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Auther: chisj chisj@foxmal.com
 * @Date: 2019-04-03 16:08
 * @Description:
 */
@Data
@Slf4j
@Component
public class WatchMessageHandler {

    /**
     * netty channel
     */
    private Channel channel;

    @Resource
    public RedisTemplate<String, Object> redisTemplate;
    @Resource
    private DmcWatchDataService dmcWatchDataService;
    @Resource
    public DmcWatchCmdRecordService dmcWatchCmdRecordService;
    @Resource
    public DmcWatchOffCmdRecordService dmcWatchOffCmdRecordService;
    @Resource
    public DmcWatchAlarmClockService dmcWatchAlarmClockService;
    @Resource
    public DmcWatchDataLocationService dmcWatchDataLocationService;
    @Resource
    private DmcWatchDataStepService dmcWatchDataStepService;
    @Resource
    private DmcWatchDataHeartService dmcWatchDataHeartService;
    @Resource
    private DmcWatchDataSleepService dmcWatchDataSleepService;
    @Resource
    private DmcWatchConfigService dmcWatchConfigService;
    @Resource
    private DmcWatchSafetyRangeService dmcWatchSafetyRangeService;
    @Resource
    private OmcRpcService omcRpcService;
    @Resource
    private DmcDeviceAlertService dmcDeviceAlertService;

    int reply = 1;
    boolean isUpdateLocation = false;
    public void handler(ChannelHandlerContext ctx, String message) {
        channel = ctx.channel();
        String IMEI = "";
        //判断是否有离线命令下发
        List<String> cmdCodeArray = null;
        String [] Items = message.split("@E#@@B#@");
        for (int m = 0; m < Items.length; m++) {
            String[] data = null;
            String cmdstr = "";
            cmdstr= "@B#@" +Items[m].replace("@E#@", "").replace("@B#@", "")+ "@E#@";
            data = cmdstr.split("\\|");
            log.info("=====>      watch message cmdstr: {}", cmdstr);
            if (data.length < 6) {

                log.error("=====> watch message data length: {}", data.length);
                continue ;
            }
            String protocol = data[2];
            log.info("=====>    watch message protocol: {}", protocol);
            if (protocol == null) {
                continue ;
            }
            IMEI = data[3];

            log.info("=====>        watch message imei: {}", IMEI);
            if (IMEI == null) {
                continue ;
            }
            if (PublicUtil.isEmpty(IMEI)) {
                // 没有imei
                log.error("=====>        watch imei is null");
                continue ;
            }

            String redisKey = RedisKeyUtil.getXxWatchKey(IMEI);
            WatchDataEntity watchDataEntity = (WatchDataEntity) redisTemplate.opsForValue().get(redisKey);
            if (PublicUtil.isEmpty(watchDataEntity)) {
                // 系统未加载该设备, 不处理该设备数据
                log.error("=====>       watch not load imei: {}", IMEI);
                return ;
            }

            // 判断是否激活,未激活的情况下下发配置数据
            if (watchDataEntity.getActivation().equals(WatchConstant.WATCH_ACTIVATION_OFF)) { // 第一次激活, 下发配置
                watchDataEntity.setActivation(WatchConstant.WATCH_ACTIVATION_ON);	// 设备激活
                // setServiceCenterConfig(watchDataEntity);	// 设置默认配置
            }
            // 设备在线
            watchDataEntity.setStatus(DeviceStatusEnum.ONLINE.getKey());

            WatchConstant.WATCH_CHANNEL_MAP.put(IMEI, ctx.channel());

            //根据 IMEI 获取离线命令
            cmdCodeArray = Lists.newArrayList(watchDataEntity.getWatchOffCmdRecordMap().keySet());
            // 根据IMEI获取待下发的语言文件
            DmcWatchAlarmClock alarmClock = watchDataEntity.getDmcWatchAlarmClock();
            // 根据CmdCodeArray判断是否还有指令下发
            if (cmdCodeArray == null || cmdCodeArray.size() == 0) {
                reply = alarmClock != null ? 1 : 0;
            } else {
                reply = 1;
            }
            switch (protocol) {
                case "001":  // 上行当前位置数据包
                    C001 m1 =  new C001(cmdstr);
                    if (m1.Protocol == null || m1.IMEI == null) {
                        break;
                    }
                    dealCmd001(m1, watchDataEntity);
                    break;
                case "003":	// 上行开机数据包
                    C003 m3 =  new C003(cmdstr);
                    if (m3.Protocol == null || m3.IMEI == null) {
                        break;
                    }
                    dealCmd003(m3, watchDataEntity);
                    break;
                case "005":	// 上行关机数据包
                    C005 m5 = new C005(cmdstr);
                    if (m5.Protocol == null || m5.IMEI == null) {
                        break;
                    }
                    dealCmd005(m5, watchDataEntity);
                    break;
                case "006":	// 上行告警数据包
                    C006 m6 = new C006(cmdstr);
                    if (m6.Protocol == null || m6.IMEI == null) {
                        break;
                    }
                    dealCmd006(m6, watchDataEntity);
                    break;
                case "009":	// 上行亲属号码设置确认数据包
                    C009 m9 = new C009(cmdstr);
                    if (m9.Protocol == null || m9.IMEI == null) {
                        break;
                    }
                    dealCmd009(m9, watchDataEntity);
                    break;
                case "012":	// 上行心率/步数/睡眠数据包
                    C012 m12 = new C012(cmdstr);
                    if (m12.Protocol == null || m12.IMEI == null) {
                        break;
                    }
                    dealCmd012(m12, watchDataEntity);
                    break;
                case "015": // 上行心率|GPS 数据周期设置确认数据包
                    C015 m15 = new C015(cmdstr);
                    if (m15.Protocol == null || m15.IMEI == null) {
                        break;
                    }
                    dealCmd015(m15, watchDataEntity);
                    break;
                case "017": // 上行 GPS 静默|余额不足语音播报|低电量提醒时间段设置确认数据包
                    C017 m17 = new C017(cmdstr);
                    if (m17.Protocol == null || m17.IMEI == null) {
                        break;
                    }
                    dealCmd017(m17, watchDataEntity);
                    break;
                case "019": // 上行逻辑开关配置确认数据包
                    C019 m19 = new C019(cmdstr);
                    if (m19.Protocol == null || m19.IMEI == null) {
                        break;
                    }
                    dealCmd019(m19, watchDataEntity);
                    break;
                case "021": // 上行设置白名单数据确认数据包
                    C021 m21 = new C021(cmdstr);
                    if (m21.Protocol == null || m21.IMEI == null) {
                        break;
                    }
                    dealCmd021(m21, watchDataEntity);
                    break;
                case "027": // 上行音量调整确认数据包
                    C027 m27 = new C027(cmdstr);
                    if (m27.Protocol == null || m27.IMEI == null) {
                        break;
                    }
                    dealCmd027(m27, watchDataEntity);
                    break;
                case "028": // 上行低电量告警数据包
                    C028 m28 = new C028(cmdstr);
                    if (m28.Protocol == null || m28.IMEI == null) {
                        break;
                    }
                    dealCmd028(m28, watchDataEntity);
                    break;
                case "029": // 上行心率异常告警数据包
                    C029 m29 = new C029(cmdstr);
                    if (m29.Protocol == null || m29.IMEI == null) {
                        break;
                    }
                    dealCmd029(m29, watchDataEntity);
                    break;
                case "033": // 上行终端数据(终端佩戴状态改变)
                    C033 m33 = new C033(cmdstr);
                    if (m33.Protocol == null || m33.IMEI == null) {
                        break;
                    }
                    dealCmd033(m33, watchDataEntity);
                    break;
                case "039": // 上行短信触发请求数据包
                    C039 m39 = new C039(cmdstr);
                    if (m39.Protocol == null || m39.IMEI == null) {
                        break;
                    }
                    dealCmd039(m39, watchDataEntity);
                    break;
                case "043": // 上行服务中心配置数据确认组包
                    C043 m43 = new C043(cmdstr);
                    if (m43.Protocol == null || m43.IMEI == null) {
                        break;
                    }
                    dealCmd043(m43, watchDataEntity);
                    break;
                case "045":	// 上行语音文件确认包
                    C045 m45 = new C045(cmdstr);
                    if (m45.Protocol == null || m45.IMEI == null) {
                        break;
                    }
                    dealCmd045(m45, watchDataEntity);
                    break;
                case "047":	// 上行闹钟配置确认包
                    C047 m47 = new C047(cmdstr);
                    if (m47.Protocol == null || m47.IMEI == null) {
                        break;
                    }
                    dealCmd047(m47, watchDataEntity);
                    break;
                case "050": // 上行时区设置确认包
                    C050 m50 = new C050(cmdstr);
                    if (m50.Protocol == null || m50.IMEI == null) {
                        break;
                    }
                    dealCmd050(m50, watchDataEntity);
                    break;
                default:
                    break;
            }

            if (reply == 1) {	// 处理离线命令
                dealOffCmd(cmdCodeArray, watchDataEntity);

                if (!watchDataEntity.isSendVoice()) {
                    setVoiceFile(watchDataEntity.getDeviceNo());
                }
            }

            ctx.channel().attr(WatchConstant.WATCH_CHANNEL_KEY).set(watchDataEntity);
            redisTemplate.opsForValue().set(redisKey, watchDataEntity);
        }
    }

    /**
     * 处理上行当前位置数据包
     *
     * @param m1
     * @param watchDataEntity
     */
    public void dealCmd001(C001 m1, WatchDataEntity watchDataEntity) {

        log.info("处理孝心手环 ==> 上行当前位置数据包 date = {}", m1.TerminalTime);

        String dateStr = DateUtil.dateToString(new Date());

        if (watchDataEntity.getTerminalTime().equals(m1.TerminalTime)) {
            return ;
        }

        watchDataEntity.setTerminalTime(m1.TerminalTime);

        isUpdateLocation = true;	// 请求定位的数据是否获取到

        watchDataEntity.setWearState(m1.WearState);		// 佩戴状态
        watchDataEntity.setPower(m1.Power);				// 电量
        watchDataEntity.setProtocol(m1.Protocol);		// 协议版本号
        watchDataEntity.setImsi(m1.IMSI);				// 手环imsi
        watchDataEntity.setLocationTime(dateStr);

        String oldBdGps = watchDataEntity.getBdGps();

        // 处理位置
        dealWatchLocation(watchDataEntity, m1.LbsType, m1.GpsString, m1.CellString, m1.WifiCellString);

        // 处理出入报警
        dealWatchLocationAlert(oldBdGps, watchDataEntity);

        // 更新设备数据
        updateWatchData(watchDataEntity);

        // 添加设备定位数据
        saveWatchLocation(watchDataEntity);

        // 002 下行确认位置数据包下发
        StringBuffer sb = new StringBuffer(WatchConstant.WATCH_TITLE);
        sb.append("|");
        sb.append(m1.Protocol);
        sb.append("|");
        sb.append(WatchConstant.WATCH_CODE_002);
        sb.append("|");
        sb.append(m1.IMEI);
        sb.append("|");
        sb.append(reply);
        sb.append("|");
        sb.append(DateUtil.nowDateStr());
        sb.append("|");
        sb.append(WatchConstant.WATCH_END);
        // @B#@|01|002|111112222233333|0|20160729173850|@E#@

        log.info("=====>   watch send message: {}", sb.toString());
        channel.writeAndFlush(Unpooled.copiedBuffer(sb.toString(), CharsetUtil.UTF_8));
    }

    /**
     * 处理上行开机数据包
     *
     * @param m3
     *
     * @param watchDataEntity
     */
    public void dealCmd003(C003 m3, WatchDataEntity watchDataEntity) {

        String dateStr = DateUtil.dateToString(new Date());

        watchDataEntity.setWearState(m3.WearState);		// 佩戴状态
        watchDataEntity.setProtocol(m3.Protocol);		// 协议版本号
        watchDataEntity.setWearVersion(m3.WearVersion);	// 终端固件版本
        watchDataEntity.setPower(m3.Power);				// 电量
        watchDataEntity.setImsi(m3.IMSI);				// 手环imsi
        watchDataEntity.setLocationTime(dateStr);

        // 处理位置
        dealWatchLocation(watchDataEntity, m3.LbsType, m3.GpsString, m3.CellString, m3.WifiCellString);

        // 更新设备数据
        updateWatchData(watchDataEntity);

        // 添加设备定位数据
        saveWatchLocation(watchDataEntity);

        // 004  下行开机确认数据包
        StringBuffer sb = new StringBuffer(WatchConstant.WATCH_TITLE);
        sb.append("|");
        sb.append(m3.Protocol);
        sb.append("|");
        sb.append(WatchConstant.WATCH_CODE_004);
        sb.append("|");
        sb.append(m3.IMEI);
        sb.append("|");
        sb.append(reply);
        sb.append("|");
        sb.append(DateUtil.nowDateStr());
        sb.append("|");
        sb.append(WatchConstant.WATCH_END);
        //String msg = "@B#@|01|004|111112222233333|0|20160729174051|@E#@";

        log.info("=====>   watch send message: {}", sb.toString());
        channel.writeAndFlush(Unpooled.copiedBuffer(sb.toString(), CharsetUtil.UTF_8));

        /**
         * @date    2020-04-17
         * @author  chisj
         * @desc    修复关机的时候，手环配置会丢失的问题
         *
         * 下发 042 指令
         */
        sendCenterConfig(watchDataEntity);

    }

    /**
     * 处理上行关机命令
     *
     * @param m5
     * @param watchDataEntity
     */
    public void dealCmd005(C005 m5, WatchDataEntity watchDataEntity) {

        // 设备离线
        watchDataEntity.setActivation(WatchConstant.WATCH_ACTIVATION_OFF);
        watchDataEntity.setProtocol(m5.Protocol);
        watchDataEntity.setPower(m5.Power);

        watchDataEntity.setStatus(DeviceStatusEnum.OFFLINE.getKey());
        watchDataEntity.setWearState(0);    // 未佩戴

        updateWatchData(watchDataEntity);
    }

    /**
     * 处理上行告警数据
     *
     * @param m6
     * @param watchDataEntity
     */
    public void dealCmd006(C006 m6, WatchDataEntity watchDataEntity) {

        String dateStr = DateUtil.dateToString(new Date());

        log.info("处理孝心手环 ==> 上行告警数据 date = {}", m6.TerminalTime);

        // 重复数据
        if (watchDataEntity.getTerminalTime().equals(m6.TerminalTime)) {
            log.warn("重复的告警数据...");
            return ;
        }

        watchDataEntity.setTerminalTime(m6.TerminalTime);
        watchDataEntity.setProtocol(m6.Protocol);
        watchDataEntity.setImsi(m6.IMSI);

        // 处理位置
        dealWatchLocation(watchDataEntity, m6.LbsType, m6.GpsString, m6.CellString, m6.WifiCellString);

        // 007 下行按键告警确认数据包
        StringBuffer sb = new StringBuffer(WatchConstant.WATCH_TITLE);
        sb.append("|");
        sb.append(m6.Protocol);
        sb.append("|");
        sb.append(WatchConstant.WATCH_CODE_007);
        sb.append("|");
        sb.append(m6.IMEI);
        sb.append("|");
        sb.append(reply);
        sb.append("|");
        // 位置 Unicode-UTF8 用于后面按键报警短信
        // sb.append(StringUtil.string2Unicode(session.getLocation()));	 //
        sb.append(watchDataEntity.getLocation());
        sb.append("|");
        // 姓名 Unicode-UTF8
        // sb.append(StringUtil.string2Unicode(session.getName()));
        sb.append(watchDataEntity.getOldmanName());
        sb.append("|");
        sb.append(DateUtil.nowDateStr());
        sb.append("|");
        sb.append(WatchConstant.WATCH_END);
//    	Stringmsg = "@B#@|01|007|111112222233333|0|\u5317\u4eac\u5e02\u6d77
//    	\u6dc0\u533a\u4e2d\u5173\u6751\u5927\u8857\u0032\u0037\u53f7\u0031
//    	\u0031\u0030\u0031\u002d\u0030\u0038\u5ba4|张三|20160805172500|@E#@";

        log.info("=====>   watch send message: {}", sb.toString());
        channel.writeAndFlush(Unpooled.copiedBuffer(sb.toString(), CharsetUtil.UTF_8));
    }

    /**
     * 处理上行亲属号码设置确认数据包
     *
     * @param m9
     * @param watchDataEntity
     */
    public void dealCmd009(C009 m9, WatchDataEntity watchDataEntity) {

        dealCmdConfirm(m9.TaskId, watchDataEntity);
    }

    /**
     * 处理上行心率/步数/睡眠数据包
     *
     * @param m12
     * @param watchDataEntity
     */
    public void dealCmd012(C012 m12, WatchDataEntity watchDataEntity) {

        String dateStr = DateUtil.dateToString(new Date());

        log.info("处理孝心手环 ==> 上行心率/步数/睡眠数据包 date = {}", m12.TerminalTime);

        // 重复数据
        if (watchDataEntity.getTerminalTime().equals(m12.TerminalTime)) {
            log.warn("重复的心率/步数/睡眠数据...");
            return ;
        }

        watchDataEntity.setTerminalTime(m12.TerminalTime);
        watchDataEntity.setProtocol(m12.Protocol);
        watchDataEntity.setImsi(m12.IMSI);
        watchDataEntity.setWearState(m12.WearState);
        watchDataEntity.setPower(m12.Power);
        watchDataEntity.setHeartRate(m12.Bat);
        watchDataEntity.setHeartTime(dateStr);
        watchDataEntity.setStep(m12.BuShu);

        // 计算公里和卡路里
        Float km = 0.0007f * m12.BuShu;
        Float cal = 0.0457755f * m12.BuShu;
        watchDataEntity.setKilometer((float)(Math.round(km * 100)) / 100);
        watchDataEntity.setCalorie((float)(Math.round(cal * 100)) / 100);

        // 计算睡眠数据
        log.info("睡眠数据 sleep = {}", m12.Sleep);
        boolean sleepFlag = true;
        String[] sleeps = m12.Sleep.split("\\&");
        if (!sleeps[0].equals("0")
                && !sleeps[1].equals("0")
                && !sleeps[2].equals("0")
                && !sleeps[3].equals("0")) {
            // 是否是重复的睡眠数据
            if (m12.Sleep.equals(watchDataEntity.getSleepQuality())) {	// 在有数据的情况,一模一样的睡眠数据
                sleepFlag = false ;
            }
            watchDataEntity.setSleepQuality(m12.Sleep);
            // 判断睡眠数据是否在1200(0400) - 2000(1200), 括号里面是0时区
            if (DateUtil.isNotSleepTime(sleeps[0]) || DateUtil.isNotSleepTime(sleeps[1])) {
                sleepFlag = false ; // 如果开始时间或者结束时间在非睡眠区间类, 不处理相关数据
            }
            // 获取手环的时区
            String timeZone = "+8";	// 默认+8时区
            DmcWatchConf dmcWatchConf = dmcWatchConfigService.queryDmcWatchConfigByDeviceId(watchDataEntity.getDeviceId());
            if (PublicUtil.isNotEmpty(dmcWatchConf)) {
                timeZone = dmcWatchConf.getTimeZone();
            }

            // 根据睡眠结束时间获取睡眠的日期, 2000(1200) - 1200(0400), 括号里面是0时区
            String sleepDate = DateUtil.getSleepDate(sleeps[1]);

            // 将睡眠开始时间,结束时间转换为手环对应的时区
            watchDataEntity.setSleepEnd(DateUtil.getSleepTimeZone(sleeps[1], timeZone));
            if (sleepDate.equals(watchDataEntity.getSleepDate())) {
                // 说明是同一天的睡眠, 睡眠开始时间不变, 睡眠结束时间改变, 浅睡、深睡、累计睡眠时间累加
                watchDataEntity.setSleepLight(DateUtil.sleepAdd(sleeps[3], watchDataEntity.getSleepLight()));
                watchDataEntity.setSleepDeep(DateUtil.sleepAdd(sleeps[2], watchDataEntity.getSleepDeep()));
                watchDataEntity.setSleepTotal(DateUtil.sleepAdd(watchDataEntity.getSleepLight(), watchDataEntity.getSleepDeep()));

                // 存储睡眠
                updateWatchDataSleep(watchDataEntity);
            } else {
                // 新一天的睡眠, 睡眠开始时间重置, 睡眠结束时间重置, 浅睡时间重置, 深睡时间重置, 累计睡眠时间重置
                watchDataEntity.setSleepStart(DateUtil.getSleepTimeZone(sleeps[0], timeZone));
                watchDataEntity.setSleepDate(sleepDate);
                watchDataEntity.setSleepDeep(sleeps[2]);
                watchDataEntity.setSleepLight(sleeps[3]);
                watchDataEntity.setSleepTotal(DateUtil.sleepAdd(watchDataEntity.getSleepLight(), watchDataEntity.getSleepDeep()));

                // 存储睡眠
                saveWatchDataSleep(watchDataEntity);
            }

        }

        // 存储心率
        saveWatchDataStep(watchDataEntity);

        // 存储步数
        saveWatchDataHeart(watchDataEntity);

        // 更新数据
        updateWatchData(watchDataEntity);

        // 回复
        // 013 下行心率/步数/睡眠确认数据包
        StringBuffer sb = new StringBuffer(WatchConstant.WATCH_TITLE);
        sb.append("|");
        sb.append(m12.Protocol);
        sb.append("|");
        sb.append(WatchConstant.WATCH_CODE_013);
        sb.append("|");
        sb.append(m12.IMEI);
        sb.append("|");
        sb.append(reply);
        sb.append("|");
        sb.append(DateUtil.nowDateStr());
        sb.append("|");
        sb.append(WatchConstant.WATCH_END);

        channel.writeAndFlush(Unpooled.copiedBuffer(sb.toString(), CharsetUtil.UTF_8));
    }

    /**
     * 处理上行心率|GPS 数据周期设置确认数据包
     *
     * @param m15
     * @param watchDataEntity
     */
    public void dealCmd015(C015 m15, WatchDataEntity watchDataEntity) {

        dealCmdConfirm(m15.TaskId, watchDataEntity);
    }

    /**
     * 处理上行 GPS 静默|余额不足语音播报|低电量提醒时间段设置确认数据包
     *
     * @param m17
     * @param watchDataEntity
     */
    public void dealCmd017(C017 m17, WatchDataEntity watchDataEntity) {

        dealCmdConfirm(m17.TaskId, watchDataEntity);
    }

    /**
     * 处理上行逻辑开关配置确认数据包
     *
     * @param m19
     * @param watchDataEntity
     */
    public void dealCmd019(C019 m19, WatchDataEntity watchDataEntity) {

        dealCmdConfirm(m19.TaskId, watchDataEntity);
    }

    /**
     * 处理上行设置白名单数据确认数据包
     *
     * @param m21
     * @param watchDataEntity
     */
    public void dealCmd021(C021 m21, WatchDataEntity watchDataEntity) {

        dealCmdConfirm(m21.TaskId, watchDataEntity);
    }

    /**
     * 处理上行音量调整确认数据包
     *
     * @param m27
     * @param watchDataEntity
     */
    public void dealCmd027(C027 m27, WatchDataEntity watchDataEntity) {

        dealCmdConfirm(m27.TaskId, watchDataEntity);
    }

    /**
     * 处理上行低电量告警数据包
     *
     * @param m28
     * @param watchDataEntity
     */
    public void dealCmd028(C028 m28, WatchDataEntity watchDataEntity) {

        watchDataEntity.setWearState(m28.WearState);
        watchDataEntity.setPower(m28.Power);
        watchDataEntity.setProtocol(m28.Protocol);

        updateWatchData(watchDataEntity);
    }

    /**
     * 处理上行心率异常告警数据包
     *
     * @param m29
     * @param watchDataEntity
     */
    public void dealCmd029(C029 m29, WatchDataEntity watchDataEntity) {

        // 当前时间  yyyy-MM-dd HH:mm:ss
        String dateStr = DateUtil.dateToString(new Date());

        watchDataEntity.setWearState(m29.WearState);	// 佩戴状态
        watchDataEntity.setPower(m29.Power);			// 电量
        watchDataEntity.setProtocol(m29.Protocol);		// 协议版本号
        watchDataEntity.setLocationTime(dateStr); 		// 定位时间
        watchDataEntity.setImsi(m29.IMSI);				// 手环imsi

        // 获取位置
        dealWatchLocation(watchDataEntity, m29.LbsType, m29.GpsString, m29.CellString, m29.WifiCellString);

        // 更新手环
        updateWatchData(watchDataEntity);

        // 存储定位数据
        saveWatchLocation(watchDataEntity);

        // 002 下行确认位置数据包下发
        StringBuffer sb = new StringBuffer(WatchConstant.WATCH_TITLE);
        sb.append("|");
        sb.append(m29.Protocol);
        sb.append("|");
        sb.append("030");
        sb.append("|");
        sb.append(m29.IMEI);
        sb.append("|");
        sb.append(reply);
        sb.append("|");
        // 位置 Unicode-UTF8 用于后面按键报警短信
        // sb.append(StringUtil.string2Unicode(session.getLocation()));
        sb.append(watchDataEntity.getLocation());
        sb.append("|");
        // 姓名 Unicode-UTF8
        // sb.append(StringUtil.string2Unicode(session.getName()));
        String oldmanName = watchDataEntity.getOldmanName();
        OldmanBedRoomBuildingVo obrbv = (OldmanBedRoomBuildingVo) redisTemplate
                .opsForValue().get(RedisKeyUtil.getOmcOldmanId(watchDataEntity.getOldmanId()));
        if (PublicUtil.isNotEmpty(obrbv)) {
            oldmanName = obrbv.getOldmanName();
            watchDataEntity.setOldmanName(oldmanName);
        }
        sb.append(oldmanName);
        sb.append("|");
        sb.append(DateUtil.nowDateStr());
        sb.append("|");
        sb.append(WatchConstant.WATCH_END);
        // @B#@|01|002|111112222233333|0|20160729173850|@E#@

        log.info("=====>   watch send message: {}", sb.toString());
        channel.writeAndFlush(Unpooled.copiedBuffer(sb.toString(), CharsetUtil.UTF_8));

    }

    /**
     * 处理上行终端佩状态戴更改数据
     *
     * @param m33
     * @param watchDataEntity
     */
    public void dealCmd033(C033 m33, WatchDataEntity watchDataEntity) {

        log.info("处理孝心手环 ==> 佩戴状态变更 date = {}", m33.TerminalTime);

        watchDataEntity.setPower(m33.Power);			// 手环电量
        watchDataEntity.setWearState(m33.WearState);	// 手环佩戴状态
        watchDataEntity.setProtocol(m33.Protocol);

        updateWatchData(watchDataEntity);

        // 034  下行终端确认数据包
        StringBuffer sb = new StringBuffer(WatchConstant.WATCH_TITLE);
        sb.append("|");
        sb.append(m33.Protocol);
        sb.append("|");
        sb.append("034");
        sb.append("|");
        sb.append(m33.IMEI);
        sb.append("|");
        sb.append(reply);
        sb.append("|");
        sb.append(DateUtil.nowDateStr());
        sb.append("|");
        sb.append(WatchConstant.WATCH_END);
        // @B#@|01|002|111112222233333|0|20160729173850|@E#@

        log.info("=====>   watch send message: {}", sb.toString());
        channel.writeAndFlush(Unpooled.copiedBuffer(sb.toString(), CharsetUtil.UTF_8));
    }

    /**
     * 处理上行短信触发请求数据包
     *
     * @param m39
     * @param watchDataEntity
     */
    public void dealCmd039(C039 m39, WatchDataEntity watchDataEntity) {
        // 暂不处理
    }

    /**
     * 处理上行服务中心配置数据确认组包
     *
     * @param m43
     * @param watchDataEntity
     */
    public void dealCmd043(C043 m43, WatchDataEntity watchDataEntity) {
        // 暂不处理
        // dealCmdConfirm(m43.TaskId, watchDataEntity);
    }

    /**
     * 处理上行语音文件配置确认包
     *
     * @param m45
     * @param watchDataEntity
     */
    public void dealCmd045(C045 m45, WatchDataEntity watchDataEntity) {

        String taskId = m45.TaskId;
        DmcWatchAlarmClock watchAlarmClock = watchDataEntity.getDmcWatchAlarmClock();
        if (watchAlarmClock == null) {
            watchAlarmClock = getWatchAlarmClock(watchDataEntity);
        }
        int voiceNowIndex = m45.PackageIndex;
        if (m45.packOver == 1) {
            voiceNowIndex++;
        }
        if (PublicUtil.isNotEmpty(watchAlarmClock)) {
            // 正在发送文件
            watchDataEntity.setSendVoice(true);
            //对语音处理 分批次下发
            byte[] voiceData = watchAlarmClock.getVoiceData(); //语音byte数据流
            //下发大小
            int voicePackLength = 1024;
            //下发次数
            int voiceCount = voiceData.length % voicePackLength == 0
                    ? voiceData.length / voicePackLength
                    : voiceData.length / voicePackLength + 1;
            int voiceNowPageLength = voicePackLength;
            if (voiceNowIndex == voiceCount) {
                voiceNowPageLength = voiceData.length % voicePackLength == 0
                        ? voicePackLength : voiceData.length % voicePackLength;
            }
            log.info("=====>             watch clock data length: {}", voiceData.length);
            log.info("=====>         watch clock data voiceCount: {}", voiceCount);
            log.info("=====> watch clock data voiceNowPageLength: {}", voiceNowPageLength);
            log.info("=====>      watch clock data voiceNowIndex: {}", voiceNowIndex);
            if (voiceNowIndex <= voiceCount) {
                // 下行亲属号码设置数据包
                StringBuffer sb = new StringBuffer(WatchConstant.WATCH_TITLE);
                sb.append("|");
                sb.append(watchDataEntity.getProtocol());
                sb.append("|");
                sb.append(WatchConstant.WATCH_CODE_044);
                sb.append("|");
                sb.append(watchDataEntity.getDeviceNo());
                sb.append("|");
                sb.append(watchAlarmClock.getClockType());
                sb.append("|");
                sb.append(0);	// amr
                sb.append("|");
                sb.append(voiceData.length);	// 文件总大小
                sb.append("|");
                sb.append(voiceCount);			// 文件总分包数
                sb.append("|");
                sb.append(voiceNowIndex);		// 文件分包索引
                sb.append("|");
                sb.append(voiceNowPageLength);		// 文件分包大小
                sb.append("|");
                String data = bytesToAscii(voiceData, (voiceNowIndex - 1) * voicePackLength, voiceNowPageLength);
                log.info("=====>                    watch clock data: {}", data);
                sb.append(data);
                sb.append("|");
                sb.append(DateUtil.nowDateStr());
                sb.append("|");
                sb.append(taskId);              // 任务Id
                sb.append("|");
                sb.append(WatchConstant.WATCH_END);

                channel.writeAndFlush(Unpooled.copiedBuffer(sb.toString(), CharsetUtil.ISO_8859_1));
            } else {
                // 发送完成
                watchDataEntity.setDmcWatchAlarmClock(null);
                // 文件发送完成
                watchDataEntity.setSendVoice(false);
                dmcWatchAlarmClockService.sendAlarmClockFinish(watchAlarmClock.getId());
            }
        }

    }

    /**
     * 处理上行闹钟配置确认包
     *
     * @param m47
     * @param watchDataEntity
     */
    public void dealCmd047(C047 m47, WatchDataEntity watchDataEntity) {

        dealCmdConfirm(m47.TaskId, watchDataEntity);
    }

    /**
     * 处理上行时区设置确认包
     *
     * @param m50
     * @param watchDataEntity
     */
    public void dealCmd050(C050 m50, WatchDataEntity watchDataEntity) {

        dealCmdConfirm(m50.TaskId, watchDataEntity);
    }

    public void dealCmdConfirm(String taskId, WatchDataEntity watchDataEntity) {

        WatchCmdProcess watchCmdProcess = WatchConstant.WATCH_CMD_PROCESS_MAP.get(taskId);
        if (PublicUtil.isNotEmpty(watchCmdProcess)) {
            watchCmdProcess.setRunning(false);
        }

        WatchConstant.WATCH_CMD_PROCESS_MAP.remove(taskId);

        Integer result = dmcWatchCmdRecordService.cmdCallbackFinish(taskId);
    }

    /**
     * 处理离线命令
     *
     * @param cmdCodeList       离线命令编码
     * @param watchDataEntity
     */
    public void dealOffCmd(List<String> cmdCodeList, WatchDataEntity watchDataEntity) {

        for (String code : cmdCodeList) {
            DmcWatchOffCmdRecord dmcWatchOffCmdRecord = watchDataEntity.getWatchOffCmdRecordMap().get(code);
            if (PublicUtil.isNotEmpty(dmcWatchOffCmdRecord)) {
                WatchCmdProcess watchCmdProcess = new WatchCmdProcess(watchDataEntity.getDeviceNo(),
                        dmcWatchOffCmdRecord.getContent(), dmcWatchOffCmdRecord.getTaskId(), dmcWatchOffCmdRecord.getCode());
                watchCmdProcess.start();
                WatchConstant.WATCH_CMD_PROCESS_MAP.put(dmcWatchOffCmdRecord.getTaskId(), watchCmdProcess);
                watchDataEntity.getWatchOffCmdRecordMap().remove(code);
            }
        }
    }

    public DmcWatchAlarmClock getWatchAlarmClock(WatchDataEntity watchDataEntity) {

        DmcWatchAlarmClock dmcWatchAlarmClock =
                dmcWatchAlarmClockService.getOneWaitSendAlarmClockByDeviceId(watchDataEntity.getDeviceId());
        if (PublicUtil.isNotEmpty(dmcWatchAlarmClock)) {
            watchDataEntity.setDmcWatchAlarmClock(dmcWatchAlarmClock);
        }

        return dmcWatchAlarmClock;
    }

    public static String bytesToAscii(byte[] bytes, int offset, int dateLen) {

        if ((bytes == null) || (bytes.length == 0) || (offset < 0) || (dateLen <= 0)) {
            return null;
        }
        if ((offset >= bytes.length) || (bytes.length - offset < dateLen)) {
            return null;
        }

        String asciiStr = null;
        byte[] data = new byte[dateLen];
        System.arraycopy(bytes, offset, data, 0, dateLen);

        try {
            asciiStr = new String(data, "ISO_8859_1");
        } catch (UnsupportedEncodingException e) {
            log.error("=====> watch bytes to ascii error: {}", e.getMessage());
        }
        return asciiStr;
    }

    /**
     * 插入手环步数数据
     *
     * @param watchDataEntity
     *
     * @return
     */
    public Integer saveWatchDataStep(WatchDataEntity watchDataEntity) {

        DmcWatchDataStep dmcWatchDataStep = new DmcWatchDataStep();

        dmcWatchDataStep.setDeviceId(watchDataEntity.getDeviceId());
        dmcWatchDataStep.setKilometer(watchDataEntity.getKilometer());
        dmcWatchDataStep.setCalorie(watchDataEntity.getCalorie());
        dmcWatchDataStep.setStep(watchDataEntity.getStep());

        return dmcWatchDataStepService.save(dmcWatchDataStep);
    }

    /**
     * 保存手环心跳数据
     *
     * @param watchDataEntity
     *
     * @return
     */
    public Integer saveWatchDataHeart(WatchDataEntity watchDataEntity) {

        DmcWatchDataHeart dmcWatchDataHeart = new DmcWatchDataHeart();

        dmcWatchDataHeart.setDeviceId(watchDataEntity.getDeviceId());
        dmcWatchDataHeart.setHeartRate(watchDataEntity.getHeartRate());

        return dmcWatchDataHeartService.save(dmcWatchDataHeart);
    }

    /**
     * 更新睡眠数据
     */
    public Integer updateWatchDataSleep(WatchDataEntity watchDataEntity) {

        DmcWatchDataSleep dmcWatchDataSleep = new DmcWatchDataSleep();

        dmcWatchDataSleep.setDeviceId(watchDataEntity.getDeviceId());
        dmcWatchDataSleep.setSleepDate(watchDataEntity.getSleepDate());
        dmcWatchDataSleep = dmcWatchDataSleepService.selectOne(dmcWatchDataSleep);
        if (PublicUtil.isNotEmpty(dmcWatchDataSleep)) {
            dmcWatchDataSleep.setSleepTotal(watchDataEntity.getSleepTotal());
            dmcWatchDataSleep.setSleepDeep(watchDataEntity.getSleepDeep());
            dmcWatchDataSleep.setSleepLight(watchDataEntity.getSleepLight());
            dmcWatchDataSleep.setSleepStart(watchDataEntity.getSleepStart());
            dmcWatchDataSleep.setSleepEnd(watchDataEntity.getSleepEnd());

            return dmcWatchDataSleepService.update(dmcWatchDataSleep);
        }

        return 0;
    }

    /**
     * 保存手环睡眠数据
     *
     * @param watchDataEntity
     *
     * @return
     */
    public Integer saveWatchDataSleep(WatchDataEntity watchDataEntity) {

        DmcWatchDataSleep dmcWatchDataSleep = new DmcWatchDataSleep();

        dmcWatchDataSleep.setDeviceId(watchDataEntity.getDeviceId());
        dmcWatchDataSleep.setSleepDate(watchDataEntity.getSleepDate());
        dmcWatchDataSleep.setSleepTotal(watchDataEntity.getSleepTotal());
        dmcWatchDataSleep.setSleepDeep(watchDataEntity.getSleepDeep());
        dmcWatchDataSleep.setSleepLight(watchDataEntity.getSleepLight());
        dmcWatchDataSleep.setSleepStart(watchDataEntity.getSleepStart());
        dmcWatchDataSleep.setSleepEnd(watchDataEntity.getSleepEnd());

        return dmcWatchDataSleepService.save(dmcWatchDataSleep);
    }

    /**
     * 更新手环数据
     *
     * @param watchDataEntity
     *
     * @return
     */
    public Integer updateWatchData(WatchDataEntity watchDataEntity) {

        DmcWatchData dmcWatchData = new DmcWatchData();
        BeanUtils.copyProperties(watchDataEntity, dmcWatchData);

        return dmcWatchDataService.update(dmcWatchData);
    }

    public Integer saveWatchLocation(WatchDataEntity watchDataEntity) {

        DmcWatchDataLocation dmcWatchDataLocation = new DmcWatchDataLocation();
        BeanUtils.copyProperties(watchDataEntity, dmcWatchDataLocation);

        return dmcWatchDataLocationService.save(dmcWatchDataLocation);
    }

    public String gpsByLbs(String lbsString) {
        // 每条基站信息对应5个参数，以逗号分隔，分别为MCC,MNC,LAC,CI,信号强度，其中信号强度的单位是dBm
        String cl = "";
        // 通过'&'分隔基站数据, eg:34073,7140,1,460,22&54552,7129,1,460,21&34772,7140,1,460,15
        // cid,lac,mnc,mcc,db(rssi)
        String lbsInfos[] = lbsString.split("\\|");
        for (int i = 0; i < lbsInfos.length; i++) {
            String lbs[] = lbsInfos[i].split(",");
            cl += Integer.parseInt(lbs[3]) + "," + Integer.parseInt(lbs[2]) + "," + Integer.parseInt(lbs[1]) + "," + Integer.parseInt(lbs[0]) + "," + Integer.parseInt(lbs[4]) + ";";
        }

        return BaiduMapUtils.gpsByLbsWifi(cl, null);
    }

    // http://www.cellocation.com/
    public String gpsByWifi(String lbsString, String wifiString) {


        // 每条基站信息对应5个参数，以逗号分隔，分别为MCC,MNC,LAC,CI,信号强度，其中信号强度的单位是dBm
        String cl = "";
        // 通过'&'分隔基站数据, eg:34073,7140,1,460,22&54552,7129,1,460,21&34772,7140,1,460,15
        // cid,lac,mnc,mcc,db(rssi)
        String lbsInfos[] = lbsString.split("&");
        for (int i = 0; i < lbsInfos.length; i++) {
            String lbs[] = lbsInfos[i].split(",");
//            int cid = Integer.parseInt(lbs[0]);
//            int lac = Integer.parseInt(lbs[1]);
//            if (mcc == 0 && mnc == 0) {
//                mnc = Integer.parseInt(lbs[2]);
//                mcc = Integer.parseInt(lbs[3]);
//            }
//            int db = Integer.parseInt(lbs[4]);
//            lbsInfo = lbsInfo + lac + "," + cid + "," + db + "|";
            cl += Integer.parseInt(lbs[3]) + "," + Integer.parseInt(lbs[2]) + "," + Integer.parseInt(lbs[1]) + "," + Integer.parseInt(lbs[0]) + "," + Integer.parseInt(lbs[4]) + ";";
        }

        // 每条WIFI热点信息对应两个参数，分别为MAC地址和信号强度
        // 通过'&'分隔wifi数据, eg:3c:46:d8:09:b0:a2,-59&dc:fe:18:b3:7c:cc,-79&28:2c:b2:e2:7d:1c,-93
        // &14:e6:e4:ac:12:c2,-88&bc:54:f9:10:8c:00,-88&cc:34:29:35:f8:66,-88
        // mac,db
        String wifiInfos[] = wifiString.split("&");
        String wl = "";
        for (int i = 0; i < wifiInfos.length; i++) {
            String wifi[] = wifiInfos[i].split(",");
            String mac = wifi[0];
            String db = wifi[1];
            wl += mac + "," + db + ";";
        }

        return BaiduMapUtils.gpsByLbsWifi(cl, wl);
    }

    public String gpsCoverLbs(String lbsString) {

        // 解析wifi和lbs数据
        int mcc = 0;	// 移动国家号码
        int mnc = 0;	// 移动网络号码
        String wifiInfo = "";
        // 通过'&'分隔wifi数据, eg:3c:46:d8:09:b0:a2,-59&dc:fe:18:b3:7c:cc,-79&28:2c:b2:e2:7d:1c,-93
        // &14:e6:e4:ac:12:c2,-88&bc:54:f9:10:8c:00,-88&cc:34:29:35:f8:66,-88
        // mac,db
        String lbsInfo = "";	// 解析后拼接的基站信息
        log.info("=====> watch cell string: {}", lbsString);
        // 通过'&'分隔基站数据, eg:34073,7140,1,460,22&54552,7129,1,460,21&34772,7140,1,460,15
        // cid,lac,mnc,mcc,db(rssi)
        String lbsInfos[] = lbsString.split("\\|");
        // 拼接 lbs
        for (int i = 0; i < lbsInfos.length; i++) {
            String lbs[] = lbsInfos[i].split(",");
            int cid = Integer.parseInt(lbs[0]);
            int lac = Integer.parseInt(lbs[1]);
            if (mcc == 0 && mnc == 0) {
                mnc = Integer.parseInt(lbs[2]);
                mcc = Integer.parseInt(lbs[3]);
            }
            int db = Integer.parseInt(lbs[4]);
            lbsInfo = lbsInfo + lac + "," + cid + "," + db + "|";
        }

        return BaiduMapUtils.gpsCoverLbsWifi(mcc, mnc, lbsInfo);
    }

    /**
     *
     * @param lbsString
     * @param wifiString
     * @return
     */
    public String gpsCoverLbsWifi(String lbsString, String wifiString) {

        // 解析wifi和lbs数据
        int mcc = 0;	// 移动国家号码
        int mnc = 0;	// 移动网络号码
        String wifiInfo = "";
        // 通过'&'分隔wifi数据, eg:3c:46:d8:09:b0:a2,-59&dc:fe:18:b3:7c:cc,-79&28:2c:b2:e2:7d:1c,-93
        // &14:e6:e4:ac:12:c2,-88&bc:54:f9:10:8c:00,-88&cc:34:29:35:f8:66,-88
        // mac,db
        String wifiInfos[] = wifiString.split("&");
        String lbsInfo = "";	// 解析后拼接的基站信息
        log.info("=====> watch wifi string: {}", wifiString);
        log.info("=====> watch cell string: {}", lbsString);
        // 通过'&'分隔基站数据, eg:34073,7140,1,460,22&54552,7129,1,460,21&34772,7140,1,460,15
        // cid,lac,mnc,mcc,db(rssi)
        String lbsInfos[] = lbsString.split("&");
        // 拼接 wifi
        for (int i = 0; i < wifiInfos.length; i++) {
            String wifi[] = wifiInfos[i].split(",");
            String mac = wifi[0];
            String db = wifi[1];
            wifiInfo += "test," + mac + "," + db + "|";
        }
        // 拼接 lbs
        for (int i = 0; i < lbsInfos.length; i++) {
            String lbs[] = lbsInfos[i].split(",");
            int cid = Integer.parseInt(lbs[0]);
            int lac = Integer.parseInt(lbs[1]);
            if (mcc == 0 && mnc == 0) {
                mnc = Integer.parseInt(lbs[2]);
                mcc = Integer.parseInt(lbs[3]);
            }
            int db = Integer.parseInt(lbs[4]);
            lbsInfo = lbsInfo + lac + "," + cid + "," + db + "|";
        }

        if (PublicUtil.isNotEmpty(wifiInfo)) {
            // 通过WiFi和LBS获取GPS
            return BaiduMapUtils.gpsCoverLbsWifi(mcc, mnc, lbsInfo, wifiInfo);
        }

        return BaiduMapUtils.gpsCoverLbsWifi(mcc, mnc, lbsInfo);
    }

    /**
     * 处理手环定位
     *
     * @param watchDataEntity
     * @param lbsType
     * @param gpsString
     * @param lbsString
     * @param wifiString
     */
    public void dealWatchLocation(WatchDataEntity watchDataEntity,
                                  Integer lbsType, String gpsString, String lbsString, String wifiString) {
        String gps = "";
        switch (lbsType) {
            case 1 :
                log.info("定位方式 ==> GPS定位");
                // 转换GPS
                gps = gpsString.replace('|', ',');
                break;
            case 2 :
                log.info("定位方式 ==> 基站定位");
//                 gps = gpsCoverLbsWifi(lbsString, wifiString);
                gps = gpsCoverLbs(lbsString);
                // gps = gpsByLbsWifi(lbsString, wifiString);
//                gps = gpsByLbs(lbsString);
                break;
            case 3 :
                log.info("定位方式 ==> WIFI定位");
                gps = gpsCoverLbsWifi(lbsString, wifiString);
//                gps = gpsByWifi(lbsString, wifiString);
                break;
        }

        // 根据GPS获取定位信息
        String bd_locations[] = BaiduMapUtils.gpsGetLocation(gps).split("&");
        String bd_gps = bd_locations[0];
        String location = bd_locations[1];

        watchDataEntity.setLbsType(lbsType);
        watchDataEntity.setBdGps(bd_gps);
        watchDataEntity.setGpsString(gps);
        watchDataEntity.setWifiString(wifiString);
        watchDataEntity.setCellString(lbsString);
        watchDataEntity.setLocation(location);
    }

    /**
     * 处理手环定位 -- 范围报警
     *
     * @param watchDataEntity
     */
    public void dealWatchLocationAlert(String oldBdGps, WatchDataEntity watchDataEntity) {

        // 范围报警
        if (PublicUtil.isNotEmpty(oldBdGps)) {

            String bdGpss[] = oldBdGps.split(",");
            String bdGpsNew[] = watchDataEntity.getBdGps().split(",");

            OldmanBedRoomBuildingVo obrbv =
                    omcRpcService.queryOldmanBedRoomBuildingByOldmanId(watchDataEntity.getOldmanId());
            if (PublicUtil.isEmpty(obrbv)) {
                log.error("孝心手环绑定的老人不存在,暂不处理手环报警");
                return ;
            }

            DmcWatchSafetyRange dmcWatchSafetyRange = new DmcWatchSafetyRange();
            dmcWatchSafetyRange.setDeviceId(watchDataEntity.getDeviceId());
            dmcWatchSafetyRange.setIsOpen(1);
            List<DmcWatchSafetyRange> list = dmcWatchSafetyRangeService.select(dmcWatchSafetyRange);
            for (DmcWatchSafetyRange r : list) {

                String ranges[] = r.getGpsString().split("\\|");

                Integer range = r.getSafetyRange();

                Point2D.Double point1 = new Point2D.Double(Double.parseDouble(bdGpss[1]),Double.parseDouble(bdGpss[0]));
                Point2D.Double point2 = new Point2D.Double(Double.parseDouble(ranges[1]),Double.parseDouble(ranges[0]));
                Point2D.Double point3 = new Point2D.Double(Double.parseDouble(bdGpsNew[1]),Double.parseDouble(bdGpsNew[0]));
                Integer distanceOld = (int) PointUtil.getDistance(point1, point2);
                Integer distanceNew = (int)PointUtil.getDistance(point3, point2);
                log.info("距离变化 distanceOld = {}, distanceNew = {}, range = {}",
                        distanceOld, distanceNew, range);

                String alertInfo = "";
                boolean flag = false;
                switch (r.getAlertWay()) {
                    case 0 :
                        // 进出报警
                        if (range.compareTo(distanceOld) >= 0) { // 圈里
                            if (range.compareTo(distanceNew) < 0) {
                                // 出去报警
                                log.info("进出报警, 出去报警");
                                alertInfo = String.format("老人[%s]出入(出去)安全范围[%s], 请前往处理!",
                                        obrbv.getOldmanName(), r.getName());
                                flag = true;
                            }
                        } else { // 圈外
                            if (range.compareTo(distanceNew) >= 0) {
                                // 进入报警
                                log.info("进出报警, 进入报警");
                                alertInfo = String.format("老人[%s]出入(进入)安全范围[%s], 请前往处理!",
                                        obrbv.getOldmanName(), r.getName());
                                flag = true;
                            }
                        }
                        break;
                    case 1 :
                        // 进出报警
                        if (range.compareTo(distanceOld) >= 0) { // 圈里
                            if (range.compareTo(distanceNew) < 0) {
                                // 出去报警
                                log.info("出去报警");
                                alertInfo = String.format("老人[%s]出去安全范围[%s], 请前往处理!",
                                        obrbv.getOldmanName(), r.getName());
                                flag = true;
                            }
                        }
                        break;
                    case 2 :
                        // 进入报警
                        if (range.compareTo(distanceOld) < 0) { // 圈外
                            if (range.compareTo(distanceNew) >= 0) { // 圈里
                                // 进入报警
                                log.info("进入报警");
                                alertInfo = String.format("老人[%s]进入安全范围[%s], 请前往处理!",
                                        obrbv.getOldmanName(), r.getName());
                                flag = true;
                            }
                        }
                        break;
                }

                if (flag) {
                    DmcDeviceAlert dmcDeviceAlert = new DmcDeviceAlert();
                    dmcDeviceAlert.setDeviceId(watchDataEntity.getDeviceId());
                    dmcDeviceAlert.setDeviceNo(watchDataEntity.getDeviceNo());
                    dmcDeviceAlert.setGroupId(watchDataEntity.getGroupId());
                    dmcDeviceAlert.setLocation(watchDataEntity.getLocation());
                    dmcDeviceAlert.setOldmanName(obrbv.getOldmanName());
                    dmcDeviceAlert.setOldmanId(watchDataEntity.getOldmanId());
                    dmcDeviceAlert.setAlertInfo(alertInfo);

                    Integer result = dmcDeviceAlertService.watchAlertMsg(dmcDeviceAlert, obrbv);
                    if (result > 0) {
                        dmcDeviceAlertService.sendDeviceAlertMsg(dmcDeviceAlert, obrbv);
                    }
                }
            }
        }
    }

    /**
     * 开机后，下发配置
     */
    public void sendCenterConfig(WatchDataEntity watchDataEntity) {

        // 查询手环的配置
        DmcWatchConf dmcWatchConf = dmcWatchConfigService.queryDmcWatchConfigByDeviceId(watchDataEntity.getDeviceId());
        if (PublicUtil.isEmpty(dmcWatchConf)) {
            return ;
        }

        String deviceNo = watchDataEntity.getDeviceNo();

        // 初始化任务Id
        String taskId = WatchUtils.getRandomString(32).toUpperCase();

        StringBuffer sb = new StringBuffer(WatchConstant.WATCH_TITLE);
        sb.append("|");
        sb.append(watchDataEntity.getProtocol());
        sb.append("|");
        sb.append(WatchConstant.WATCH_CODE_042);
        sb.append("|");
        sb.append(deviceNo);
        sb.append("|");
        sb.append(dmcWatchConf.getHeartRate());  // 心率周期
        sb.append("|");
        sb.append(dmcWatchConf.getGpsRate());  // GPS周期
        sb.append("|");
        sb.append(dmcWatchConf.getGpsPeriod());  // GPS 静默时间段
        sb.append("|");
        sb.append(dmcWatchConf.getBalancePeriod());  // 余额不足时间段
        sb.append("|");
        sb.append(dmcWatchConf.getPowerPeriod());  // 低电量提醒时间段
        sb.append("|");
        sb.append(dmcWatchConf.getGpsSwitch());  // gps开关 0-关闭 1-开启
        sb.append("|");
        sb.append(dmcWatchConf.getWhiteSwitch());  // 白名单开关
        sb.append("|");
        sb.append(dmcWatchConf.getWhiteList());  // 白名单
        sb.append("|");
        sb.append("10086&102");  // 短信余额查询方式
        sb.append("|");
        sb.append(dmcWatchConf.getVolume()); // 音量大小 1 - 7
        sb.append("|");
        sb.append(dmcWatchConf.getHeartThreshad());  // 心率阈值
        sb.append("|");
        sb.append(dmcWatchConf.getRedKeyNumber());  // 红键亲属号码
        sb.append("|");
        sb.append(dmcWatchConf.getYellowKeyNumber());  // 黄键亲属号码
        sb.append("|");
        sb.append(dmcWatchConf.getGreenKeyNumber());  // 绿键亲属号码
        sb.append("|");
        sb.append("0");  // 是否需要升级标志
        sb.append("|");
        sb.append(DateUtil.nowDateStr());
        sb.append("|");
        sb.append(taskId); // 任务Id
        sb.append("|");
        sb.append(WatchConstant.WATCH_END);
        //@B#@|01|042|111112222233333|5|10|00002359|00002300|01001800|1|1|132
        // 45225552&15223636632|10086&\u0031\u0030\u0032|7|45&150|1362215222
        //2|15962225212|17052225452|0|20160729174051|@E#@

        log.info("=====>   watch send message: {}", sb.toString());
        channel.writeAndFlush(Unpooled.copiedBuffer(sb.toString(), CharsetUtil.UTF_8));
    }

    /**
     * 设置服务中心配置  待定？
     *
     * @param watchDataEntity
     */
    public void setServiceCenterConfig(WatchDataEntity watchDataEntity) {

        String deviceNo = watchDataEntity.getDeviceNo();

        // 初始化任务Id
        String taskId = WatchUtils.getRandomString(32).toUpperCase();

        StringBuffer sb = new StringBuffer(WatchConstant.WATCH_TITLE);
        sb.append("|");
        sb.append(watchDataEntity.getProtocol());
        sb.append("|");
        sb.append(WatchConstant.WATCH_CODE_042);
        sb.append("|");
        sb.append(deviceNo);
        sb.append("|");
        sb.append(10);  // 心率周期
        sb.append("|");
        sb.append(60);  // GPS周期
        sb.append("|");
        sb.append("22000700");  // GPS 静默时间段
        sb.append("|");
        sb.append("22000700");  // 余额不足时间段
        sb.append("|");
        sb.append("22000700");  // 低电量提醒时间段
        sb.append("|");
        sb.append(1);  // gps开关 0-关闭 1-开启
        sb.append("|");
        sb.append(0);  // 白名单开关
        sb.append("|");
        sb.append("888888");  // 白名单
        sb.append("|");
        sb.append("10086&102");  // 短信余额查询方式
        sb.append("|");
        sb.append("7"); // 音量大小 1 - 7
        sb.append("|");
        sb.append("50&150");  // 心率阈值
        sb.append("|");
        sb.append("");  // 红键亲属号码
        sb.append("|");
        sb.append("");  // 黄键亲属号码
        sb.append("|");
        sb.append("");  // 绿键亲属号码
        sb.append("|");
        sb.append("0");  // 是否需要升级标志
        sb.append("|");
        sb.append(DateUtil.nowDateStr());
        sb.append("|");
        sb.append(taskId); // 任务Id
        sb.append("|");
        sb.append(WatchConstant.WATCH_END);
        //@B#@|01|042|111112222233333|5|10|00002359|00002300|01001800|1|1|132
        // 45225552&15223636632|10086&\u0031\u0030\u0032|7|45&150|1362215222
        //2|15962225212|17052225452|0|20160729174051|@E#@

        log.info("=====>   watch send message: {}", sb.toString());
        channel.writeAndFlush(Unpooled.copiedBuffer(sb.toString(), CharsetUtil.UTF_8));
        //saveAndSendWatchCmd(deviceNo, sb.toString(), taskId, WatchConstant.WATCH_CODE_046, watchDataEntity);

        // 清空提醒
        setAlarmClock(deviceNo, "");
//        setAlarmClock(deviceNo, "0&0&1200&0000000");
    }

    /**
     * 下发闹钟铃声文件
     *
     * @param deviceNo  the device no
     */
    public void setVoiceFile(String deviceNo) {

        log.info("设置孝心手环 ==> 铃声文件 deviceNo = [{}]");

        WatchDataEntity watchDataEntity = (WatchDataEntity) redisTemplate
                .opsForValue().get(RedisKeyUtil.getXxWatchKey(deviceNo));
        if (PublicUtil.isEmpty(watchDataEntity)) {
            log.error("孝心手环[{}]尚未绑定...", deviceNo);
            return ;
        }

        if (channel == null || !channel.isActive()) {
            log.error("孝心手环[{}]已经离线...", deviceNo);
            return ;
        }

        if (watchDataEntity.isSendVoice()) {
            log.warn("孝心手环正在下发铃声...");
        }

        // 获取离线铃声文件
        DmcWatchAlarmClock dmcWatchAlarmClock = getWatchAlarmClock(watchDataEntity);
        if (dmcWatchAlarmClock == null) {
            log.warn("孝心手环正在铃声下发完成...");
            return;
        }

        // 待下发的铃声
        watchDataEntity.setDmcWatchAlarmClock(dmcWatchAlarmClock);

        // 正在下发铃声文件
        watchDataEntity.setSendVoice(true);

        // 初始化任务Id
        String taskId = WatchUtils.getRandomString(32).toUpperCase();

        // 对语音处理 分批次下发
        // 语音byte数据流
        byte[] voiceData = dmcWatchAlarmClock.getVoiceData();
        // 下发序号
        int voiceNowIndex = 1;
        // 下发大小
        int voicePackLength = 1024;
        // 下发次数
        int voiceCount = voiceData.length % voicePackLength == 0
                ? voiceData.length / voicePackLength
                : voiceData.length / voicePackLength + 1;
        // 当前包大小
        int voiceNowPageLength = voicePackLength;
        if (voiceNowIndex == voiceCount) {
            voiceNowPageLength = voiceData.length % voicePackLength == 0
                    ? voicePackLength : voiceData.length % voicePackLength;
        }
        log.info("铃声分包情况 ==> length = {}, count = {}, nowPackIndex = {}, nowPackLength = {}",
                voiceData.length, voiceCount, voiceNowIndex, voiceNowPageLength);

        if (voiceNowIndex <= voiceCount) {
            // 下行亲属号码设置数据包
            StringBuffer sb = new StringBuffer(WatchConstant.WATCH_TITLE);
            sb.append("|");
            sb.append(watchDataEntity.getProtocol());
            sb.append("|");
            sb.append(WatchConstant.WATCH_CODE_044);
            sb.append("|");
            sb.append(deviceNo);
            sb.append("|");
            sb.append(dmcWatchAlarmClock.getClockType());
            sb.append("|");
            sb.append(0);    // amr
            sb.append("|");
            sb.append(voiceData.length);    // 文件总大小
            sb.append("|");
            sb.append(voiceCount);          // 文件总分包数
            sb.append("|");
            sb.append(voiceNowIndex);       // 文件分包索引
            sb.append("|");
            sb.append(voiceNowPageLength);  // 文件分包大小
            sb.append("|");
            String date = bytesToAscii(voiceData, (voiceNowIndex - 1) * voicePackLength, voiceNowPageLength);
            sb.append(date);                // 文件分包大小
            sb.append("|");
            sb.append(DateUtil.nowDateStr());
            sb.append("|");
            sb.append(taskId); // 任务Id
            sb.append("|");
            sb.append(WatchConstant.WATCH_END);
            channel.writeAndFlush(Unpooled.copiedBuffer(sb.toString(), CharsetUtil.ISO_8859_1));
        } else { // 发送完成
            watchDataEntity.setDmcWatchAlarmClock(null);
            // 文件发送完成
            watchDataEntity.setSendVoice(false);

            dmcWatchAlarmClockService.sendAlarmClockFinish(dmcWatchAlarmClock.getId());
        }
    }

    /**
     * 设置闹钟
     *
     * @param deviceNo  the device no
     * @param clocks    闹钟
     *                  闹钟类型[0-吃药提醒 1-喝水提醒 2-运动提醒 3-自定义 1]&
     *                  闹钟开关[0-为关, 1-为开]&
     *                  闹钟时间&重复规律[1111100，表示周一到周五工作，周六/周日不工作]
     *                  多组闹钟用 % 分隔
     */
    public void setAlarmClock(String deviceNo, String clocks) {

        log.info("设置孝心手环 ==> 智能提醒 deviceNo = [{}], clocks = [{}]",
                deviceNo, clocks);

        WatchDataEntity watchDataEntity = (WatchDataEntity) redisTemplate
                .opsForValue().get(RedisKeyUtil.getXxWatchKey(deviceNo));
        if (PublicUtil.isEmpty(watchDataEntity)) {
            log.error("孝心手环[{}]尚未绑定...", deviceNo);
            return ;
        }

        // 初始化任务Id
        String taskId = WatchUtils.getRandomString(32).toUpperCase();

        StringBuffer sb = new StringBuffer(WatchConstant.WATCH_TITLE);
        sb.append("|");
        sb.append(watchDataEntity.getProtocol());
        sb.append("|");
        sb.append(WatchConstant.WATCH_CODE_046);
        sb.append("|");
        sb.append(deviceNo);
        sb.append("|");
        sb.append(clocks);
        sb.append("|");
        sb.append(DateUtil.nowDateStr());
        sb.append("|");
        sb.append(taskId); // 任务Id
        sb.append("|");
        sb.append(WatchConstant.WATCH_END);
//        @B#@|01|046|111112222233333|0&1&0830&1111111%1&1&1630&11
//        11100|20160715153805|0255BB90395C475E9D6155AF98B383875|@E#@

        saveAndSendWatchCmd(deviceNo, sb.toString(), taskId, WatchConstant.WATCH_CODE_046, watchDataEntity);
    }

    /**
     * 设置时间段 GPS静默|余额不足语音播报|低电量提醒
     *
     * @param deviceNo  the device no
     * @param type      类型
     *                  1-GPS静默; 2-语音播报; 3-低电量提醒
     * @param start     起始时间段   时分，不足位用 0 填充(range:0000-2359)
     * @param end       结束时间段   时分，不足位用 0 填充(range:0000-2359)
     */
    public void setPeriod(String deviceNo, int type, String start, String end) {

        log.info("设置孝心手环 ==> 时间段 deviceNo = [{}], type = [{}], start = [{}], end = [{}]",
                deviceNo, type, start, end);

        WatchDataEntity watchDataEntity = (WatchDataEntity) redisTemplate
                .opsForValue().get(RedisKeyUtil.getXxWatchKey(deviceNo));
        if (PublicUtil.isEmpty(watchDataEntity)) {
            log.error("孝心手环[{}]尚未绑定...", deviceNo);
            return ;
        }

        // 初始化任务Id
        String taskId = WatchUtils.getRandomString(32).toUpperCase();

        StringBuffer sb = new StringBuffer(WatchConstant.WATCH_TITLE);
        sb.append("|");
        sb.append(watchDataEntity.getProtocol());
        sb.append("|");
        sb.append(WatchConstant.WATCH_CODE_016);
        sb.append("|");
        sb.append(deviceNo);
        sb.append("|");
        sb.append(type);
        sb.append("|");
        sb.append(start);
        sb.append("|");
        sb.append(end);
        sb.append("|");
        sb.append(DateUtil.nowDateStr());
        sb.append("|");
        sb.append(taskId); // 任务Id
        sb.append("|");
        sb.append(WatchConstant.WATCH_END);
        // String msg = "@B#@|01|016|111112222233333|2|2100|0600|20160715162720|0255BB9039
        // 5C475E9D6155AF98B38387|@E#@";

        saveAndSendWatchCmd(deviceNo, sb.toString(), taskId, WatchConstant.WATCH_CODE_016, watchDataEntity);
    }

    /**
     * 设置时区
     *
     * @param deviceNo  the device no
     * @param timeZone  时区 +08 北京时区
     */
    public void setTimeZone(String deviceNo, String timeZone) {

        log.info("设置孝心手环 ==> 时区 deviceNo = [{}], timeZone = [{}]",
                deviceNo, timeZone);

        WatchDataEntity watchDataEntity = (WatchDataEntity) redisTemplate
                .opsForValue().get(RedisKeyUtil.getXxWatchKey(deviceNo));
        if (PublicUtil.isEmpty(watchDataEntity)) {
            log.error("孝心手环[{}]尚未绑定...", deviceNo);
            return ;
        }

        // 初始化任务Id
        String taskId = WatchUtils.getRandomString(32).toUpperCase();

        // 下行时区设置
        StringBuffer sb = new StringBuffer(WatchConstant.WATCH_TITLE);
        sb.append("|");
        sb.append(watchDataEntity.getProtocol());
        sb.append("|");
        sb.append(WatchConstant.WATCH_CODE_049);
        sb.append("|");
        sb.append(deviceNo);
        sb.append("|");
        sb.append(timeZone);
        sb.append("|");
        sb.append(taskId); // 任务Id
        sb.append("|");
        sb.append(WatchConstant.WATCH_END);
//        @B#@|01|049|111112222233333|+08|0255BB90395C475E9D6155AF98B38
//        387|@E#@

        saveAndSendWatchCmd(deviceNo, sb.toString(), taskId, WatchConstant.WATCH_CODE_049, watchDataEntity);
    }

    /**
     * 设置孝心手环逻辑开关
     *
     * @param deviceNo  the device no
     * @param type      开关类别
     *                  1-GPS 开关 2-白名单开关 3-黄键短信开关 4-红键短信开关
     * @param switchs   开关标志
     *                  开关标志 0-关闭	1-开启
     */
    public void setLogicSwitch(String deviceNo, int type, int switchs) {

        log.info("设置孝心手环 ==> 逻辑开关 deviceNo = [{}], type = [{}], switchs = [{}]",
                deviceNo, type, switchs);

        WatchDataEntity watchDataEntity = (WatchDataEntity) redisTemplate
                .opsForValue().get(RedisKeyUtil.getXxWatchKey(deviceNo));
        if (PublicUtil.isEmpty(watchDataEntity)) {
            log.error("孝心手环[{}]尚未绑定...", deviceNo);
            return ;
        }

        // 初始化任务Id
        String taskId = WatchUtils.getRandomString(32).toUpperCase();

        // 下行逻辑开关配置开关
        StringBuffer sb = new StringBuffer(WatchConstant.WATCH_TITLE);
        sb.append("|");
        sb.append(watchDataEntity.getProtocol());
        sb.append("|");
        sb.append(WatchConstant.WATCH_CODE_018);
        sb.append("|");
        sb.append(deviceNo);
        sb.append("|");
        sb.append(type);
        sb.append("|");
        sb.append(switchs);
        sb.append("|");
        sb.append(DateUtil.nowDateStr());
        sb.append("|");
        sb.append(taskId); // 任务Id
        sb.append("|");
        sb.append(WatchConstant.WATCH_END);
//        @B#@|01|018|111112222233333|1|0|20160715165125|0255BB90395C475E9
//        D6155AF98B383875|@E#@

        saveAndSendWatchCmd(deviceNo, sb.toString(), taskId, WatchConstant.WATCH_CODE_018, watchDataEntity);
    }

    /**
     * 设置孝心手环白名单列表
     *
     * @param deviceNo      the  device no
     * @param whiteList     白名单列表 每个电话号码之间用‘&’连接
     */
    public void setWhiteList(String deviceNo, String whiteList) {

        log.info("设置孝心手环 ==> 白名单列表 deviceNo = [{}], whiteList = [{}]",
                deviceNo, whiteList);

        WatchDataEntity watchDataEntity = (WatchDataEntity) redisTemplate
                .opsForValue().get(RedisKeyUtil.getXxWatchKey(deviceNo));
        if (PublicUtil.isEmpty(watchDataEntity)) {
            log.error("孝心手环[{}]尚未绑定...", deviceNo);
            return ;
        }

        if (PublicUtil.isEmpty(whiteList)) {
            // 如果不传数据，最后一个号码不会限制白名单
            whiteList = "888888";
        }

        // 初始化任务Id
        String taskId = WatchUtils.getRandomString(32).toUpperCase();

        // 下行音量调整数据包
        StringBuffer sb = new StringBuffer(WatchConstant.WATCH_TITLE);
        sb.append("|");
        sb.append(watchDataEntity.getProtocol());
        sb.append("|");
        sb.append(WatchConstant.WATCH_CODE_020);
        sb.append("|");
        sb.append(deviceNo);
        sb.append("|");
        sb.append(whiteList);
        sb.append("|");
        sb.append(DateUtil.nowDateStr());
        sb.append("|");
        sb.append(taskId); // 任务Id
        sb.append("|");
        sb.append(WatchConstant.WATCH_END);
//        @B#@|01|020|111112222233333|13255644458&15233652145|20160715165
//        125|0255BB90395C475E9D6155AF98B383875|@E#@

        saveAndSendWatchCmd(deviceNo, sb.toString(), taskId, WatchConstant.WATCH_CODE_020, watchDataEntity);
    }

    /**
     * 设置孝心手环音量大小
     *
     * @param deviceNo  the device no
     * @param volume    音量大小 1 - 7
     */
    public void setVolume(String deviceNo, int volume) {

        log.info("设置孝心手环 ==> 音量大小 deviceNo = [{}], volume = [{}]",
                deviceNo, volume);

        WatchDataEntity watchDataEntity = (WatchDataEntity) redisTemplate
                .opsForValue().get(RedisKeyUtil.getXxWatchKey(deviceNo));
        if (PublicUtil.isEmpty(watchDataEntity)) {
            log.error("孝心手环[{}]尚未绑定...", deviceNo);
            return ;
        }

        // 初始化任务Id
        String taskId = WatchUtils.getRandomString(32).toUpperCase();

        // 下行音量调整数据包
        StringBuffer sb = new StringBuffer(WatchConstant.WATCH_TITLE);
        sb.append("|");
        sb.append(watchDataEntity.getProtocol());
        sb.append("|");
        sb.append(WatchConstant.WATCH_CODE_026);
        sb.append("|");
        sb.append(deviceNo);
        sb.append("|");
        sb.append(volume);
        sb.append("|");
        sb.append(DateUtil.nowDateStr());
        sb.append("|");
        sb.append(taskId); // 任务Id
        sb.append("|");
        sb.append(WatchConstant.WATCH_END);
//        @B#@|01|026|111112222233333|9|20160715162720|0255BB90395C475E9D
//        6155AF98B38387|@E#@

        saveAndSendWatchCmd(deviceNo, sb.toString(), taskId, WatchConstant.WATCH_CODE_026, watchDataEntity);

    }

    /**
     * 设置孝心手环心率或GPS定位数据上传间隔
     *
     * @param deviceNo  the device no
     * @param rateType  the rate type
     *                  1 - 心率周期; 2 - GPS周期
     * @param rateUnit  the rate unit
     *                  0 - 300 分钟
     */
    public void setHeartOrGpsRate(String deviceNo, int rateType, int rateUnit) {

        log.info("设置孝心手环 ==> 心率或GPS上传间隔 deviceNo = [{}], rateType = [{}], rateUnit = [{}]",
                deviceNo, rateType, rateUnit);

        WatchDataEntity watchDataEntity = (WatchDataEntity) redisTemplate
                .opsForValue().get(RedisKeyUtil.getXxWatchKey(deviceNo));
        if (PublicUtil.isEmpty(watchDataEntity)) {
            log.error("孝心手环[{}]尚未绑定...", deviceNo);
            return ;
        }

        // 初始化任务Id
        String taskId = WatchUtils.getRandomString(32).toUpperCase();

        // 下行亲属号码设置数据包
        StringBuffer sb = new StringBuffer(WatchConstant.WATCH_TITLE);
        sb.append("|");
        sb.append(watchDataEntity.getProtocol());
        sb.append("|");
        sb.append(WatchConstant.WATCH_CODE_014);
        sb.append("|");
        sb.append(deviceNo);
        sb.append("|");
        sb.append(rateType);
        sb.append("|");
        sb.append(rateUnit);
        sb.append("|");
        sb.append(DateUtil.nowDateStr());
        sb.append("|");
        sb.append(taskId); // 任务Id
        sb.append("|");
        sb.append(WatchConstant.WATCH_END);
        // String msg = "@B#@|01|008|111112222233333|13425155855&12345678901&13412345678
        //|20160715155852|0255BB90395C475E9D6155AF98B38387|@E#@";

        saveAndSendWatchCmd(deviceNo, sb.toString(), taskId, WatchConstant.WATCH_CODE_014, watchDataEntity);
    }

    private void saveAndSendWatchCmd(String deviceNo, String cmd, String taskId, String code, WatchDataEntity watchDataEntity) {

        Channel channel = WatchConstant.WATCH_CHANNEL_MAP.get(deviceNo);
        boolean online = false;
        if (channel != null) {
            if (channel.isActive()) {
                online = true;
            } else {
                log.warn("孝心手环[{}]连接断开...", deviceNo);
            }
        } else {
            log.warn("孝心手环[{}]不在线...", deviceNo);
        }

        if (online) {
            // 在线命令
            WatchCmdProcess watchCmdProcess =
                    new WatchCmdProcess(deviceNo, cmd, taskId, code);
            watchCmdProcess.start();
            WatchConstant.WATCH_CMD_PROCESS_MAP.put(taskId, watchCmdProcess);
            // 存储下发命令
            saveWatchCmdRecord(code, cmd, watchDataEntity.getDeviceId(),
                    taskId, channel.toString(), WatchConstant.WATCH_ON_CMD);
        } else {
            // 离线命令
            saveWatchCmdOffRecord(code, cmd, taskId, watchDataEntity);
        }

    }

    /**
     * set family number
     *
     * @param deviceNo      device no
     * @param familyNumbers family numbers (red&yellow&green)
     */
    public void setFamilyNumber(String deviceNo, String familyNumbers) {

        log.info("设置孝心手环 ==> 亲情号码 deviceNo = [{}], familyNumbers = [{}]",
                deviceNo, familyNumbers);

        WatchDataEntity watchDataEntity = (WatchDataEntity) redisTemplate
                .opsForValue().get(RedisKeyUtil.getXxWatchKey(deviceNo));
        if (PublicUtil.isEmpty(watchDataEntity)) {
            log.error("孝心手环[{}]尚未绑定...", deviceNo);
            return ;
        }

        // 初始化任务Id
        String taskId = WatchUtils.getRandomString(32).toUpperCase();

        // 下行亲属号码设置数据包
        StringBuffer sb = new StringBuffer(WatchConstant.WATCH_TITLE);
        sb.append("|");
        sb.append(watchDataEntity.getProtocol());
        sb.append("|");
        sb.append(WatchConstant.WATCH_CODE_008);
        sb.append("|");
        sb.append(deviceNo);
        sb.append("|");
        sb.append(familyNumbers);
        sb.append("|");
        sb.append(DateUtil.nowDateStr());
        sb.append("|");
        sb.append(taskId); // 任务Id
        sb.append("|");
        sb.append(WatchConstant.WATCH_END);

        saveAndSendWatchCmd(deviceNo, sb.toString(), taskId, WatchConstant.WATCH_CODE_008, watchDataEntity);
    }

    /**
     * save watch cmd record
     *
     * @param code      消息码
     * @param content   消息内容
     * @param deviceId  设备Id
     * @param taskId    任务Id
     * @param channel   channel信息
     * @param isOff     是否为离线命令 0-不是 1-是
     */
    public void saveWatchCmdRecord(String code, String content, Long deviceId,
                                   String taskId, String channel, Integer isOff) {

        DmcWatchCmdRecord dmcWatchCmdRecord = new DmcWatchCmdRecord();
        dmcWatchCmdRecord.setCode(code);
        dmcWatchCmdRecord.setContent(content);
        dmcWatchCmdRecord.setDeviceId(deviceId);
        dmcWatchCmdRecord.setTaskId(taskId);
        dmcWatchCmdRecord.setChannel(channel);
        dmcWatchCmdRecord.setIsOff(isOff);
        dmcWatchCmdRecord.setIsSend(WatchConstant.IS_SEND);

        dmcWatchCmdRecordService.save(dmcWatchCmdRecord);
    }

    /**
     * save watch cmd off record
     *
     * @param code
     * @param content
     * @param taskId
     * @param watchDataEntity
     */
    public void saveWatchCmdOffRecord(String code, String content, String taskId,
                                      WatchDataEntity watchDataEntity) {

        // 保存离线命令
        DmcWatchOffCmdRecord dmcWatchOffCmdRecord = new DmcWatchOffCmdRecord();
        dmcWatchOffCmdRecord.setCode(code);
        dmcWatchOffCmdRecord.setContent(content);
        dmcWatchOffCmdRecord.setDeviceId(watchDataEntity.getDeviceId());
        dmcWatchOffCmdRecord.setTaskId(taskId);

        dmcWatchOffCmdRecordService.save(dmcWatchOffCmdRecord);

        // 判断是否有同一种待下发的离线命令
        DmcWatchOffCmdRecord offCmdRecord = watchDataEntity.getWatchOffCmdRecordMap().get(code);
        if (PublicUtil.isNotEmpty(offCmdRecord)) {
            // 取消该离线命令
            offCmdRecord.setReplaceId(dmcWatchOffCmdRecord.getId());
            dmcWatchOffCmdRecordService.update(offCmdRecord);

            watchDataEntity.getWatchOffCmdRecordMap().put(code, dmcWatchOffCmdRecord);
        }

    }

    /**
     * 初始化配置
     *
     */
//    public void initConfig(String deviceNo) {
//
//        log.info("初始化孝心手环配置 ==> deviceNo = [{}]", deviceNo);
//
//        WatchDataEntity watchDataEntity = (WatchDataEntity) redisTemplate
//                .opsForValue().get(RedisKeyUtil.getXxWatchKey(deviceNo));
//        if (PublicUtil.isEmpty(watchDataEntity)) {
//            log.error("孝心手环[{}]尚未绑定...", deviceNo);
//            return ;
//        }
//
//        setServiceCenterConfig(watchDataEntity);
//    }

    /**
     * 断开连接
     *
     * @param deviceNo
     */
    public void clear(String deviceNo) {



    }
}
